package testcasegenerator.clp.classlevel;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.sql.rowset.Predicate;



import graph.mpg.Block;
import graph.mpg.TestPath;

import spec.ocl_mpg.OCLTree;
import spec.ocl_mpg.TreeNode;
import spec.state.Transition;

public class CLPconverter {
	
	private LinkedList<SpecPredicate> spec_list = new LinkedList<SpecPredicate>();
	private LinkedList<PathPredicate> path_list = new LinkedList<PathPredicate>();
	
	private String spec_code = null;
	
	
	public CLPconverter(List<OCLTree> list , LinkedList<Transition> alltransition ){
		convertOCLtoCLP(list);
		convertGuardtoCLP(alltransition);
		setClassEventName();
/*
		//show information
		for(int i=0;i<=spec_list.size()-1;i++){
			System.out.println(  "   ");
			
			
			if(spec_list.get(i).getClass().toString().equals("class testcasegenerator.clp.classlevel.MethodPredicate")){
				//System.out.println("Class Name : " + spec_list.get(i).getclassName());
				//System.out.println("Event  : " + spec_list.get(i).getevent());
				System.out.println("ClassEventName  : " + ((MethodPredicate) spec_list.get(i)).getClassEventName());
				System.out.println("inv  : " +((MethodPredicate) spec_list.get(i)).getinv());
				System.out.println("pre  : " +((MethodPredicate) spec_list.get(i)).getpre());
				System.out.println("post  : " +((MethodPredicate) spec_list.get(i)).getpost());
				System.out.println("Var  : " + spec_list.get(i).getvar_list());
				System.out.println("Param  : " + spec_list.get(i).getparam_list());
				System.out.println("returnType  : " + ((MethodPredicate) spec_list.get(i)).getreturnType());
				
			}
			else{
				//System.out.println(spec_list.get(i).getClass().toString());
				//System.out.println("Class Name : " + spec_list.get(i).getclassName());
				//System.out.println("Event  : " + spec_list.get(i).getevent());
				System.out.println("GuardName  : " + ((GuardPredicate) spec_list.get(i)).getClassEventName());
				
				System.out.println("Action  : " +spec_list.get(i).getaction());
				System.out.println("Var  : " + spec_list.get(i).getvar_list());
				System.out.println("Param  : " + spec_list.get(i).getparam_list());
			}
		}
		
	*/	
	}
    
	public void convertPathtoCLP(TestPath path) {
		PathPredicate predicate = new PathPredicate();
		predicate.setpathName("testpath");
		predicate.setpath(path);
        predicate.setspec_list(spec_list);		
		
		path_list.add(predicate);
		
	}

	/*
	 * set ClassEventName  
	 * ex:ClassName : Account
	 *    Event : increase     
	 * 
	 *    ClassEventName:accountIncrease
	 *    
	 *    GuardEventName:accountDecreaseGuard + i
	 */
	private void setClassEventName() {
		int k=1;
		for(int i=0;i<=spec_list.size()-1;i++){
			
			if(spec_list.get(i).getClass().toString().equals("class testcasegenerator.clp.classlevel.MethodPredicate")){
				MethodPredicate predicate = (MethodPredicate) spec_list.get(i);
				predicate.setClassEventName(predicate.getclassName().toLowerCase() + predicate.getevent().substring(0,1).toUpperCase()+predicate.getevent().substring(1,predicate.getevent().length()).toLowerCase());
			}
			if(spec_list.get(i).getClass().toString().equals("class testcasegenerator.clp.classlevel.GuardPredicate")){
				GuardPredicate predicate = (GuardPredicate) spec_list.get(i);
				predicate.setClassEventName(predicate.getclassName().toLowerCase() + predicate.getevent().substring(0,1).toUpperCase()+predicate.getevent().substring(1,predicate.getevent().length()).toLowerCase() + "Guard"+k);
				k++;
			}
		}
		
	}

	/*
	 * covert OCL constraint to MethodPredicate
	 */
	private void convertOCLtoCLP(List<OCLTree> list) {
		TreeNode inv = null;
		for(OCLTree tree : list){
			/*
			if(tree.getConstraintType().equals("invariant")){
				MethodPredicate predicate = new MethodPredicate();
				predicate.setclassName(tree.getClassName());
				predicate.setevent(tree.getMethodName());
				predicate.setinv(tree.getTree());
				predicate.setparam_list(tree.getParam_list());
				predicate.setvar_list(tree.getVar_list());
				predicate.setreturnType(tree.getReturnType());	
				predicate.setOCLTree(tree);
				spec_list.add(predicate);
			}
			*/
			
			if(tree.getConstraintType().equals("invariant")){
				inv = tree.getTree();
			}
			
			
			if(tree.getConstraintType().equals("precondition")){
				boolean flag = false;//true mean have same name predicate exist
				for(int i=0;i<=spec_list.size()-1;i++){
					if (((MethodPredicate) spec_list.get(i)).getevent().equals(tree.getMethodName())) {
						((MethodPredicate) spec_list.get(i)).setpre(tree.getTree());	
						flag = true;
					}
				}
				//no same name predicate exist , new a predicate
			    if(flag == false){
					MethodPredicate predicate = new MethodPredicate();
					predicate.setclassName(tree.getClassName());
					predicate.setevent(tree.getMethodName());
					predicate.setinv(inv);
					predicate.setpre(tree.getTree());
					predicate.setparam_list(tree.getParam_list());
					predicate.setvar_list(tree.getVar_list());
					predicate.setreturnType(tree.getReturnType());	
					predicate.setOCLTree(tree);
					spec_list.add(predicate);
			    }
				
			}
			
			else{
				boolean flag = false;//true mean have same name predicate exist
				for(int i=0;i<=spec_list.size()-1;i++){
					if (((MethodPredicate) spec_list.get(i)).getevent().equals(tree.getMethodName())) {
						((MethodPredicate) spec_list.get(i)).setpost(tree.getTree());	
						flag = true;
					}
				}
				//no same name predicate exist , new a predicate
				if(flag == false){
					MethodPredicate predicate = new MethodPredicate();
					predicate.setclassName(tree.getClassName());
					predicate.setevent(tree.getMethodName());
					predicate.setinv(inv);
					predicate.setpost(tree.getTree());
					predicate.setparam_list(tree.getParam_list());
					predicate.setvar_list(tree.getVar_list());
					predicate.setreturnType(tree.getReturnType());
					predicate.setOCLTree(tree);
					spec_list.add(predicate);
				}
				
			}
		}
		
	}
	
	/*
	 * convert UML State diagram guard to GuardPredicate
	 */
	private void convertGuardtoCLP(LinkedList<Transition> AllTransitions){
		for(Transition transition : AllTransitions){
			
			if(transition.guard != null){
				
				GuardPredicate predicate = new GuardPredicate();
				predicate.setevent(transition.getevent());	
				predicate.setaction(transition.guard);
				spec_list.add(predicate);	
			}
		}
		
		setGuardClaaName();
		setGuardVarList();
		setGuardParamList();	
	}

	
    /*
     * set Guard param
     */
	private void setGuardParamList() {
		for(int i=0;i<=spec_list.size()-1;i++){
			if(spec_list.get(i).getClass().toString().equals("class testcasegenerator.clp.classlevel.GuardPredicate")){
				for(int j=0;j<=spec_list.size()-1;j++){
					if(spec_list.get(j).getClass().toString().equals("class testcasegenerator.clp.classlevel.MethodPredicate")){
						if(spec_list.get(i).getevent().equals(spec_list.get(j).getevent())){
							spec_list.get(i).setparam_list((spec_list.get(j)).getparam_list());
						}		
					}						
				}
				
			}
		}
		
	}

	/*
	 * set Guard var
	 */
	private void setGuardVarList() {
		for(int i=0;i<=spec_list.size()-1;i++){
			if(spec_list.get(i).getClass().toString().equals("class testcasegenerator.clp.classlevel.GuardPredicate")){
				for(int j=0;j<=spec_list.size()-1;j++){
					if(spec_list.get(j).getClass().toString().equals("class testcasegenerator.clp.classlevel.MethodPredicate")){
						if(spec_list.get(i).getevent().equals(spec_list.get(j).getevent())){
							spec_list.get(i).setvar_list((spec_list.get(j)).getvar_list());
						}		
					}
				}
				
			}
		}
		
		
	}

	/*
	 * set GuardClassName
	 */
	private void setGuardClaaName() {
		for(int i=0;i<=spec_list.size()-1;i++){
			if(spec_list.get(i).getClass().toString().equals("class testcasegenerator.clp.classlevel.GuardPredicate")){
				for(int j=0;j<=spec_list.size()-1;j++){
					if(spec_list.get(j).getClass().toString().equals("class testcasegenerator.clp.classlevel.MethodPredicate")){
						if(spec_list.get(i).getevent().equals(spec_list.get(j).getevent())){
							spec_list.get(i).setclassName((spec_list.get(j)).getclassName());
						}		
					}					
				}
				
			}
		}	
	}
	
	
	/*
	 * genarate testcasegenerator.clp.classlevel code
	 */
	public String generateCLPCode(){
		String code = "%include\n";
		code += ":- lib(ic).\n";
		code += "\n";
		TreeNode inv = new TreeNode();
		for(SpecPredicate predicate : spec_list ){	
				code += predicate.generateCLP();
		}
		spec_code = code;
		
		for(PathPredicate predicate : path_list){
			code += predicate.generateCLP();
		}
		
		
		return code;
	}
	
	public void writeCLPCodeFile(String code){
		try {
		
			FileWriter writer = new FileWriter("CLPCode.ecl");
			writer.write(code);
			writer.flush();
			writer.close();

		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
		
	}
	
	public LinkedList<SpecPredicate> getspec_list(){
		return spec_list;
	}
	
	public String getspec_code(){
		return spec_code;
	}
	
}
